﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Expect.Core.Errors;

namespace Expect.Core
{
    /// <summary>
    /// Status of a RunnableElement
    /// </summary>
    public class Status
    {
        private bool? success;

        /// <summary>
        /// Indicate wether the element execution was successful
        /// </summary>
        public bool? Success
        {
            get
            {
                return this.success;
            }
            set
            {
                this.success = value;
                if (value.HasValue && value.Value)
                {
                    _nestedErrors.Clear();
                }
            }
        }

        private List<NFitError> _nestedErrors = new List<NFitError>();
        /// <summary>
        /// The nested execution error 
        /// </summary>
        public List<NFitError> NestedErrors
        {
            get { return _nestedErrors; }
            private set { _nestedErrors = value; }
        }

        /// <summary>
        /// Indicate if the execution is successful
        /// </summary>
        public bool IsSuccessful
        {
            get
            {
                return Success.HasValue && Success.Value;
            }
        }

        /// <summary>
        /// The date and time at wich the execution start
        /// </summary>
        public DateTime? StartTime
        {
            get;
            internal set;
        }

        /// <summary>
        /// The date and time at wich the execution end
        /// </summary>
        public DateTime? EndTime
        {
            get;
            internal set;
        }

        /// <summary>
        /// The duration of the execution
        /// </summary>
        public TimeSpan Duration
        {
            get
            {
                if (!StartTime.HasValue || !EndTime.HasValue)
                    return TimeSpan.Zero;

                return (EndTime.Value - StartTime.Value);
            }
        }

        /// <summary>
        /// Add an error to the list
        /// </summary>
        /// <param name="err"></param>
        public void AddError(NFitError err)
        {
            if (!NestedErrors.Contains(err))
            {
                NestedErrors.Add(err);
            }
        }

        /// <summary>
        /// Indicate if the status has an error of the provided type
        /// </summary>
        /// <typeparam name="T">The type of the error to search for</typeparam>
        /// <returns>true if the status has an error of that type</returns>
        public bool HasError<T>() where T : NFitError
        {
            if (NestedErrors.Any(e => e.GetType() == typeof(T)))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Indicate if the status has an error of the provided type and that match the predicate
        /// </summary>
        /// <typeparam name="T">The type of the error to search for</typeparam>
        /// <param name="checkError"></param>
        /// <returns>true if the status has an error of that type and matching the predicate</returns>
        public bool HasError<T>(Func<T, bool> checkError) where T : NFitError
        {
            if (HasError<T>() && (checkError ==null || NestedErrors.Any(e => checkError((T)e))))
            {
                return true;
            }

            return false;
        }


    }
}
